#include "app_device.h"
#include "app_common.h"
#include "app_buff.h"
#include "app_mqtt.h"
#include "app_message.h"
#include "app_pool.h"
#include "log.h"
#include "fcntl.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

static device_t *device = NULL;

/**
 * @brief 设备初始化
 * @param dev_file_name 设备的文件地址
 * @return 设备结构体指针
 */
device_t *app_device_init(char *dev_file_name)
{
    device_t *dev = (device_t *)malloc(sizeof(device_t));
    if (dev == NULL)
    {
        log_error("device init error");
        return NULL;
    }
    // 设置设备文件名
    dev->dev_file_name = dev_file_name;
    // 打开设备文件
    dev->dev_fd = open(dev_file_name, O_RDWR);
    if (dev->dev_fd < 0)
    {
        perror("打开设备文件失败！");
        return NULL;
    }
    // 为预处理方法的初始直 设置为null
    dev->post_read = NULL;
    dev->priv_write = NULL;
    // 缓冲区
    dev->up_buffer = app_buff_init(1024);
    dev->down_buffer = app_buff_init(1024);
    // 运行情况
    dev->is_running = false;
    // 上次写入时间
    dev->last_write_ts_ms = 0;
    // 写入间隔
    dev->write_interval_ms = 200;

    device = dev;
   // log_info("设备初始化成功！");
    return dev;
}

/**
 * @brief 启动设备读取操作
 * @return 0: 成功, -1: 失败
 * @note 设备设置一个唯一的 \
 * 启动从蓝牙串口中读取数据 （上行线路的开端）\
 * 向消息队列模块中注册接受数据后的处理函数 （下行线路的开始）
 */
int app_device_start(void)
{
    if (device->is_running)
    {
        return 0;
    }
    device->is_running = 1;
    // 启动从蓝牙串口中读取数据 （上行线路的开端）
    int res = pthread_create(&device->dev_read_pthread, NULL, app_device_read, NULL);
    if (res < 0)
    {
        perror("创建线程失败！");
        return -1;
    }
    
    // 向消息队列模块中注册接受数据后的处理函数 （下行线路的开始）
    app_mqtt_register_recv(app_device_recv_from_mqtt);

    // log_debug("设备启动成功！");
    return 0;
}

/**
 * @brief 从蓝牙芯片中读取数据（异步方法）
 * @note 从蓝牙芯片中读取数据 \
 * 要做读后预处理 转换格式 \
 * 写入到上行缓冲区中 \
 * 安排线程池执行 后续工作 （发送mqtt）
 */
void *app_device_read(void *arg)
{
    
    while (device->is_running)
    {
        // 从蓝牙芯片中读取数据
        char data_buff[128]; 
        int read_size = read(device->dev_fd, data_buff, 128);

        if (read_size <= 0)
        {
            continue;
        }
        // 要做读后预处理 转换格式 
        if (device->post_read)
        {
            read_size = device->post_read(data_buff,read_size);  
        }
        
        if (read_size <= 0)
        {
            continue;
        }
        // 写入到上行缓冲区中 
        int res = app_buff_write(device->up_buffer, data_buff, read_size);
        if (res < 0)
        {
            perror("写入上行缓冲区失败！");
            continue;
        }
        // 安排线程池执行 后续工作 （发送mqtt）
        app_pool_register((void *)app_device_send2mqtt, NULL);
    }
    return NULL;
}

/**
 * @brief 从缓冲区中读取数据 写入到mqtt中 （异步方法）
 * @note 从上行缓冲区中读取数据 \
 * 做数据转换格式 to json \
 * 发送到mqtt中 
 */
void *app_device_send2mqtt(void *arg)
{
    // 从上行缓冲区中读取数据 
    char data_buff[128] = {0};
    int read_size = app_buff_read(device->up_buffer, data_buff, 128);
    if (read_size <= 0)
    {
        perror("读取上行缓冲区失败！");
        return NULL;
    }
    log_info("读取到数据：");
    app_common_printf_hex(data_buff, read_size);
    // 做数据转换格式
    char *json = app_message_bytes2json(data_buff, read_size); 
    if (json == NULL)
    {
        perror("转换格式失败！");
        return NULL;
    }
    // 发送到mqtt中
    int ret = app_mqtt_send(json, strlen(json));
    if (ret < 0)
    {
        perror("发送mqtt失败！");
        return NULL;
    }
    return NULL;
}

/**
 * @brief 从mqtt中接受数据 写入到缓冲区  （注册给消息队列模块）
 * @note 把从mqtt中接受的json进行转换 转换为字节数组 \
 * 写入到下行缓冲区中 \
 * 安排线程池执行 后续工作 （发送蓝牙芯片）
 */
int app_device_recv_from_mqtt(char *json_data, int data_len)
{
    // 把从mqtt中接受的json进行转换 转换为字节数组
    char data_buff[128] = {0}; 
    int new_data_len = app_message_json2bytes(json_data,data_buff, data_len);
    // 写入到下行缓冲区中
    int ret = app_buff_write(device->down_buffer, data_buff, new_data_len);
    if (ret < 0)
    {
        perror("写入下行缓冲区失败！");
        return -1;
    }

    // 安排线程池执行 后续工作 （发送蓝牙芯片）
    app_pool_register((void *)app_device_write, NULL);
    
    return 0;
}

/**
 * @brief 从下行缓冲区中读取数据 向蓝牙芯片中写入数据（异步方法）
 * @note 从下行缓冲区中读取数据 \
 * 如果有数据则进行写前预处理 \
 * 写入到蓝牙芯片中（串口文件） 
 */
void *app_device_write(void *arg)
{
    // 从下行缓冲区中读取数据 
    char data_buff[128] = {0};
    int data_size = app_buff_read(device->down_buffer, data_buff, 128);
    if (data_size <= 0)
    {
        perror("读取下行缓冲区失败！");
        return NULL;
    }
    
    // 如果有数据则进行写前预处理 
    if (device->priv_write)
    {
        data_size = device->priv_write(data_buff,data_size);  
    }

    // 写入到蓝牙芯片中（串口文件） 
    // 写入数据之前要控制频率 必须达到间隔才能写入
    long long now_ts_ms = app_common_getCurrentTime();
    if (device->last_write_ts_ms > 0)
    {
        int curr_interval = now_ts_ms - device->last_write_ts_ms;
        if (curr_interval < device->write_interval_ms)
        {
            // 要求间隔 - 当前的时间间隔 = 需要等待的时间
            usleep((device->write_interval_ms - curr_interval) * 1000);
        }
    }
    
    int ret = write(device->dev_fd, data_buff, data_size);
    if (ret < 0)
    {
        perror("写入设备数据失败！");
        return NULL;
    }
    return NULL;
}

/**
 * @brief 设备的销毁
 */
void app_device_destroy(void)
{
    // 结束读取操作
    device->is_running = false;
    pthread_cancel(device->dev_read_pthread);

    app_buff_destroy(device->up_buffer);
    app_buff_destroy(device->down_buffer);

    close(device->dev_fd);

    free(device); 
}
